package net.cyue.web.easyquery.core.config.toml;

import net.cyue.util.IdentifierStringConverter;
import net.cyue.util.StringUtil;
import net.cyue.web.easyquery.core.config.ConfigException;
import net.cyue.web.easyquery.core.config.ConfigItemValue;
import net.cyue.web.easyquery.core.db.QueryType;
import net.cyue.web.easyquery.core.db.SQLType;
import net.cyue.web.easyquery.core.http.HTTPRequestMethod;
import net.cyue.web.easyquery.core.http.data.QueryParameter;
import net.cyue.web.easyquery.core.util.TOMLUtil;
import org.tomlj.TomlArray;
import org.tomlj.TomlTable;

import java.util.ArrayList;
import java.util.List;

public class TOMLConfigItemValue extends ConfigItemValue {

    public static ConfigItemValue fromTable(TomlTable table)
        throws ConfigException
    {
        String typeStr = TOMLUtil.getString(table, "type", Type.ADDITIONAL.name());
        Type type = Type.valueOf(typeStr.toUpperCase());
        if (type.equals(Type.API)) {
            List<String> pathList = new ArrayList<>();
            if (table.isArray("path")) {
                TomlArray pathArr = TOMLUtil.getArray(
                    table,
                    "path",
                    TOMLUtil.getArray(
                        table,
                        "paths"
                    )
                );
                pathArr.toList().forEach(p -> pathList.add(p.toString()));
            } else if (table.isString("path")) {
                String path = TOMLUtil.getString(table, "path");
                if (!StringUtil.isBlank(path)) {
                    pathList.add(path);
                }
            }
            if (pathList.isEmpty()) {
                throw new ConfigException("Invalid API config item: " + table);
            }

            API api = new API();
            api.type = Type.API;
            api.description = table.getString("description");
            api.paths = pathList.toArray(new String[0]);
            api.sql = table.getString("sql");
            String preHandlerClassName = TOMLUtil.getString(table, "prehandler", TOMLUtil.getString(table, "preHandler"));
            if (!StringUtil.isBlank(preHandlerClassName)) {
                api.setPreHandler(preHandlerClassName);
            }
            try {
                api.sqlType = SQLType.valueOf(
                    IdentifierStringConverter.camelCase2Snake(
                        TOMLUtil.getString(table, "sqlType", SQLType.UNKNOWN.name())
                    ).toUpperCase()
                );
            } catch (IllegalArgumentException e) {
                LOGGER.warn(e.getMessage(), e);
                api.sqlType = SQLType.UNKNOWN;
            }
            try {
                api.queryType = QueryType.valueOf(
                    IdentifierStringConverter.camelCase2Snake(
                        TOMLUtil.getString(table, "queryType", QueryType.QUERY_LIST.name())
                    ).toUpperCase()
                );
            } catch (IllegalArgumentException e) {
                LOGGER.warn(e.getMessage(), e);
                api.queryType = QueryType.QUERY_LIST;
            }

            // 请求方法
            String defaultMethodName = HTTPRequestMethod.GET.name();
            if (api.sqlType == SQLType.UPDATE) {
                defaultMethodName = HTTPRequestMethod.POST.name();
            }
            api.method = HTTPRequestMethod.valueOf(
                TOMLUtil
                    .getString(table, "method", defaultMethodName)
                    .toUpperCase()
            );

            api.pageParameter = TOMLUtil.getString(
                table,
                "pageParameter",
                DEFAULT_PAGE_PARAMETER
            );
            api.pageSizeParameter = TOMLUtil.getString(
                table,
                "pageSizeParameter",
                DEFAULT_PAGE_SIZE_PARAMETER
            );

            // 分页查询 默认需要 page 与 pageSize 参数
            if (api.queryType == QueryType.QUERY_PAGE || api.queryType == QueryType.PAGE) {
                api.addQueryParameter(
                    new QueryParameter(
                        api.pageParameter,
                        QueryParameter.Type.INT,
                        "页数",
                        true,
                        1
                    )
                );
                api.addQueryParameter(
                    new QueryParameter(
                        api.pageSizeParameter,
                        QueryParameter.Type.INT,
                        "每页数量",
                        true,
                        DEFAULT_PAGE_SIZE
                    )
                );
            }

            // 查询参数
            if (TOMLUtil.hasKey(table, "parameters")) {
                TomlArray array = table.getArray("parameters");
                List<QueryParameter> list = parseParameterArray(array);
                api.addQueryParameterList(list);
            }
            if (TOMLUtil.hasKey(table, "parameter")) {
                TomlArray array = table.getArray("parameter");
                List<QueryParameter> list = parseParameterArray(array);
                api.addQueryParameterList(list);
            }

            return api;
        } else {
            Additional additional = new Additional();
            String name = table.getString("name");
            String key = table.getString("key");
            if (name == null && key == null) {
                throw new ConfigException("Invalid additional config item: " + table);
            }
            additional.type = Type.ADDITIONAL;
            additional.description = table.getString("description");
            if (key != null) {
                additional.setKey(key);
            } else {
                additional.group = table.getString("group");
                additional.name = name;
            }
            additional.value = table.getString("value");
            return additional;
        }
    }

    private static List<QueryParameter> parseParameterArray(TomlArray array)
        throws ConfigException
    {
        if (array == null) {
            return new ArrayList<>();
        }

        List<QueryParameter> list = new ArrayList<>(array.size());
        for (int i = 0; i < array.size(); i++) {
            Object p = array.get(i);
            if (p instanceof String) {
                QueryParameter parameter = new QueryParameter((String) p);
                list.add(parameter);
            } else if (p instanceof TomlTable) {
                TomlTable parameterTable = array.getTable(i);
                QueryParameter parameter = parseParameterTable(parameterTable);
                list.add(parameter);
            } else {
                throw new ConfigException("Invalid parameter: " + p);
            }
        }
        return list;
    }

    private static QueryParameter parseParameterTable(TomlTable table) {
        String name = table.getString("name");
        String description = table.getString("description");
        boolean required = TOMLUtil.getBoolean(table, "required", false);
        QueryParameter.Type parameterType =
            QueryParameter.Type.valueOf(
                TOMLUtil
                    .getString(table, "type", QueryParameter.Type.ANY.name())
                    .toUpperCase()
            );
        Object defaultValue = null;
        if (
            parameterType.equals(QueryParameter.Type.ANY) ||
            parameterType.equals(QueryParameter.Type.STRING)
        ) {
            defaultValue = TOMLUtil.getString(
                    table,
                    "default",
                    TOMLUtil.getString(
                        table,
                        "defaultValue",
                        null
                    )
                );
        } else if (
            parameterType.equals(QueryParameter.Type.INT) ||
            parameterType.equals(QueryParameter.Type.INTEGER) ||
            parameterType.equals(QueryParameter.Type.LONG)
        ) {
            defaultValue = TOMLUtil.getLong(
                    table,
                    "default",
                    TOMLUtil.getLong(
                        table,
                        "defaultValue",
                        null
                    )
                );
        } else if (
            parameterType.equals(QueryParameter.Type.FLOAT) ||
            parameterType.equals(QueryParameter.Type.DOUBLE) ||
            parameterType.equals(QueryParameter.Type.NUMBER)
        ) {
            defaultValue = TOMLUtil.getDouble(
                    table,
                    "default",
                    TOMLUtil.getDouble(
                        table,
                        "defaultValue",
                        null
                    )
                );
        } else if (
            parameterType.equals(QueryParameter.Type.BOOL) ||
            parameterType.equals(QueryParameter.Type.BOOLEAN)
        ) {
            defaultValue = TOMLUtil.getBoolean(
                    table,
                    "default",
                    TOMLUtil.getBoolean(
                        table,
                        "defaultValue",
                        null
                    )
                );
        }
        return new QueryParameter(name, parameterType, description, required, defaultValue);
    }
}
